package cn.xorange.commons.security.interceptor;

import cn.xorange.commons.security.annotation.RateLimiter;
import cn.xorange.commons.security.constants.InterceptConstants;
import cn.xorange.commons.security.constants.SecurityCacheKeys;
import cn.xorange.commons.security.exception.SecurityException;
import cn.xorange.commons.utils.Collect.CollectUtils;
import cn.xorange.commons.utils.cache.ICacheService;
import cn.xorange.commons.utils.http.ServletUtils;
import cn.xorange.commons.utils.ip.IpUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author : yangjian
 * date : 2024/1/25
 * description :
 */
public class InterceptRepeatSubmit {

    @Resource
    ICacheService cacheService;

    /**
     * 设置和添加访问次数
     * @param key 缓存 key:xxx
     */
    private Integer checkAccessCache(Long cycleTime,String key){
        List<Long> lst = cacheService.getCacheObject(key);
        if(CollectUtils.isNotEmpty(lst)){
            lst.removeIf(timeOut -> timeOut + cycleTime < System.currentTimeMillis());
            //CacheUtils.getList(key).removeIf(timeOut ->((Long)timeOut)<=System.currentTimeMillis());
        }else {
            lst = new ArrayList<>();
        }
        lst.add(System.currentTimeMillis());

        cacheService.setCacheObject(key, lst, cycleTime, TimeUnit.MILLISECONDS);
        return lst.size();
    }

    /**
     * 检测范围时间允许访问次数
     */
    public void checkRateLimiter(Method method){

        long cycleTime = InterceptConstants.WEB_ACCESS_LIMIT_SECONDS;
        int cycleCount = InterceptConstants.WEB_ACCESS_LIMIT_COUNT;
        if (method.isAnnotationPresent(RateLimiter.class)){
            RateLimiter rateLimiter = method.getAnnotation(RateLimiter.class);
            cycleTime = rateLimiter.cycleTime();
            cycleCount = rateLimiter.cycleCount();
        }

        //cache结构
        // Map<String,Map<ip,CacheEntity(List<createTime>,expireTime)>
        HttpServletRequest request = ServletUtils.getRequest();
        String ip = IpUtils.getIpAddr(request);
        String key = SecurityCacheKeys.webAttackCatchKey(ip,request);
        // 将访问添加至缓存 获取缓存中周期内的次数
        int num = this.checkAccessCache(cycleTime,key);
        if (num > cycleCount){
            throw SecurityException.interceptRateLimiter();
        }

    }

}
